package com.blank.shop.security.filter;

import com.blank.shop.security.controller.ValidateCodeController;
import com.blank.shop.security.handler.MyAuthenticationFailureHandler;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.Objects;

/**
 * <br/>Date 2021/9/10
 * <br/>Time 1:33:09
 *
 * @author _blank
 */

@Slf4j
public class ImageValidateCodeFilter extends OncePerRequestFilter {

    /**
     * 处理登录请求
     */
    public static final String LOGIN_PROCESSING_URL = "/authentication/form.html";

    /**
     * 验证码超时时间
     */
    public static final long CAPTCHA_TIMEOUT = Duration.ofSeconds(15L).toMillis();

    protected final MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Setter
    private String filterUrl = LOGIN_PROCESSING_URL;

    public ImageValidateCodeFilter(MyAuthenticationFailureHandler myAuthenticationFailureHandler) {
        // 容器注入bean
        this.myAuthenticationFailureHandler = myAuthenticationFailureHandler;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (StringUtils.equals(this.filterUrl, request.getRequestURI())
                && StringUtils.equalsIgnoreCase(HttpMethod.POST.name(), request.getMethod())) {
            try {
                this.validate(new ServletWebRequest(request, response));
            } catch (ValidateCodeException e) {
                this.myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    protected void validate(ServletWebRequest servletWebRequest) throws ServletRequestBindingException {
        // session 验证码
        final String sessionCaptchaCode = (String) servletWebRequest.getAttribute(ValidateCodeController.SESSION_CAPTCHA_KEY, RequestAttributes.SCOPE_SESSION);
        // 前端用户验证码
        final String requestVerificationCode = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "verificationCode");

        if (StringUtils.isBlank(requestVerificationCode)) {
            throw new ValidateCodeException("验证码的值不能为空！");
        }
        if (Objects.isNull(sessionCaptchaCode)) {
            throw new ValidateCodeException("验证码不存在！");
        }
        final String[] millisAndCode = StringUtils.split(sessionCaptchaCode, "::");
        if (System.currentTimeMillis() - CAPTCHA_TIMEOUT > Long.parseLong(millisAndCode[0])) {
            // fixme 有问题
            servletWebRequest.removeAttribute(ValidateCodeController.SESSION_CAPTCHA_KEY, RequestAttributes.SCOPE_SESSION);
            throw new ValidateCodeException("验证码已过期");
        }
        if (!StringUtils.equalsIgnoreCase(millisAndCode[1], requestVerificationCode)) {
            throw new ValidateCodeException("验证码不匹配");
        }
        servletWebRequest.removeAttribute(ValidateCodeController.SESSION_CAPTCHA_KEY, RequestAttributes.SCOPE_SESSION);
    }

}
